package com.cupdata.sms.executor;

import com.cupdata.sms.config.ConfigProperties;
import com.cupdata.sms.core.ThreadPoolStatus;
import org.apache.kafka.common.protocol.types.Field;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.RejectedExecutionHandler;

/**
 * @author: zda
 * @description: 启动类
 * @date: 2024/4/30 14:22
 */
@EnableConfigurationProperties(ConfigProperties.class)
public class CusThreadPoolHolder implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean, Ordered {

    private static Map<String, CusThreadPoolExecutor> beanMap = new ConcurrentHashMap<>(4);
    private static ApplicationContext applicationContext;
    @Autowired
    private ConfigProperties configProperties;
    private CusThreadPoolHolder(){}

    @Override
    public void destroy() throws Exception {

    }

    @Override
    public void afterSingletonsInstantiated() {
        if(!CollectionUtils.isEmpty(configProperties.getThreadPoolStatuses())){
            for (ThreadPoolStatus ts:configProperties.getThreadPoolStatuses()){
                CusThreadPoolExecutor cusThreadPoolExecutor = new CusThreadPoolExecutor();
                if(ts.getPoolName()!=null){
                    cusThreadPoolExecutor.setPoolName(ts.getPoolName());
                } else {
                    continue;
                }
                if(ts.getCorePoolSize()!=null) cusThreadPoolExecutor.setCorePoolSize(ts.getCorePoolSize());
                if(ts.getTaskDescribe()!=null) cusThreadPoolExecutor.setTaskDescribe(ts.getTaskDescribe());
                if(ts.getMaxPoolSize()!=null) cusThreadPoolExecutor.setMaxPoolSize(ts.getMaxPoolSize());
                if(ts.getKeepAliveTime()!=null) cusThreadPoolExecutor.setKeepAliveTime(ts.getKeepAliveTime());
                if(ts.getDequeSize()!=null) cusThreadPoolExecutor.setDequeSize(ts.getDequeSize());
                if(ts.getPoolName()!=null) cusThreadPoolExecutor.setPoolName(ts.getPoolName());
                if(ts.getAlarmCount()!=null) cusThreadPoolExecutor.setAlarmCount(ts.getAlarmCount());
                if(ts.getAlarmSize()!=null) cusThreadPoolExecutor.setAlarmSize(ts.getAlarmSize());
                if(ts.getRejected()!=null) cusThreadPoolExecutor.setRejectedExecutionHandler(applicationContext.getBean(ts.getRejected(), RejectedExecutionHandler.class));
                cusThreadPoolExecutor.start();
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(cusThreadPoolExecutor.getClass());
                BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
                BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) (((ConfigurableApplicationContext)applicationContext).getBeanFactory());
                beanFactory.registerBeanDefinition(ts.getPoolName(), beanDefinition);
            }
        }
        this.obtainAllThreadPoolExecutor();
    }

    private void obtainAllThreadPoolExecutor() {
        beanMap = getBeansOfType(CusThreadPoolExecutor.class);
        if (CollectionUtils.isEmpty(beanMap)) {
            throw new RuntimeException("未定义线程池，服务未能正常启动，请开启默认线程池或自定义线程池");
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        CusThreadPoolHolder.applicationContext = applicationContext;
    }

    @Override
    public int getOrder() {
        return 2;
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> tClass) {
        return applicationContext.getBeansOfType(tClass);
    }
    public static <T> T getBean(String beanName, Class<T> tClass) {
        return applicationContext.getBean(beanName, tClass);
    }

    public static CusThreadPoolExecutor getPool(String name){
        return beanMap.get(name);
    }

    public static CusThreadPoolExecutor getDefaultPool(){
        return beanMap.get("default-thread-pool");
    }
}
